package com.george.auth.service;

import cn.hutool.crypto.SecureUtil;
import com.george.auth.constants.TokenConstants;
import com.george.auth.vo.LoginUserVO;
import com.george.common.api.feign.user.UserServiceFeign;
import com.george.common.entity.dto.user.LoginUserDTO;
import com.george.common.entity.dto.user.ScbUserDTO;
import com.george.common.entity.vo.user.ScbUserVO;
import com.george.common.exception.BaseException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.crypto.SecretKey;
import java.util.Objects;

/**
 * @Title: UserNamePwdServiceImpl.java
 * @Description: 用户名密码登录获取用户信息处理逻辑
 * @Author: George
 * @Date: 2023/6/13 16:43
 */
@Slf4j
@Service
public class UserNamePwdServiceImpl implements UserDetailsService {
    public static SecretKey secretKey;

    static {
        //登录密码加密方式
        secretKey = SecureUtil.generateKey(TokenConstants.AES_WAY, TokenConstants.AES_SECRET.getBytes());
    }

    @Resource
    private TokenServiceImpl tokenService;
    @Resource
    private AuthenticationManager authenticationManager;
    @Resource
    private UserServiceFeign userServiceFeign;

    /**
     * 用户账号查询逻辑
     *
     * @param userAccount
     * @author :George
     * @date : 2022/4/2 15:21
     * @return: org.springframework.security.core.userdetails.UserDetails
     */
    @Override
    public UserDetails loadUserByUsername(String userAccount) throws UsernameNotFoundException {
        ScbUserDTO scbUserDTO = userServiceFeign.getUserInfoByUsername(userAccount);
        if (Objects.isNull(scbUserDTO)) {
            log.info("登录用户：{} 不存在.", userAccount);
            throw new BaseException("登录用户：" + userAccount + " 不存在");
        }
        return createLoginUser(scbUserDTO);
    }

    public UserDetails createLoginUser(ScbUserDTO scbUserDTO) {
        ScbUserVO scbUserVO = new ScbUserVO();
        BeanUtils.copyProperties(scbUserDTO, scbUserVO);
        UserDetails userDetails = new LoginUserVO(scbUserVO);
        return userDetails;
    }

    /**
     * 根据用户名和密码登录
     *
     * @param userName 用户名
     * @param password 密码
     * @author :George
     * @date : 2022/3/31 10:43
     * @return: com.unique.entity.dto.LoginUserDTO
     */
    public LoginUserDTO loginByUserNameAndPwd(String userName, String password) {
        // 用户验证
        Authentication authentication = null;
        try {
            try {
                password = SecureUtil.aes(secretKey.getEncoded()).decryptStr(password);
            } catch (Exception e) {
                throw new BaseException("密码加密错误");
            }
            // 该方法会去调用 UserDetailsServiceImpl.loadUserByUsername，实质是上面重写的loadUserByUsername方法
            authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(userName, password));
            LoginUserVO loginUser = (LoginUserVO) authentication.getPrincipal();
            // 生成token
            return tokenService.createToken(loginUser);
        } catch (Exception e) {
            if (e instanceof BadCredentialsException) {
                throw new BaseException("用户名或密码错误");
            } else {
                throw new BaseException(e.getMessage());
            }
        }
    }

    public static void main(String[] args) {
        String rawPassword = "123456";
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        // 加密密码
        String encodedPassword = passwordEncoder.encode(rawPassword);
        System.out.println("加密后的密码：" + encodedPassword);
        // 验证密码
        boolean isPasswordMatch = passwordEncoder.matches(rawPassword, encodedPassword);
        System.out.println("密码匹配结果：" + isPasswordMatch);
    }
}
